package com.brillilab.service.core.method.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import javax.annotation.Resource;

import com.brillilab.domain.po.method.MethodTypeHide;
import com.brillilab.service.core.method.IMethodTypeHideService;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.brillilab.dao.mapper.method.MethodTypeMapper;
import com.brillilab.domain.enums.common.BoolEnum;
import com.brillilab.domain.enums.common.IsDeleteEnum;
import com.brillilab.domain.enums.method.MethodTypeLevelEnum;
import com.brillilab.domain.po.method.MethodType;
import com.brillilab.domain.vo.method.MethodTypeDetailVo;
import com.brillilab.domain.vo.method.RecommendMethodTypeVo;
import com.brillilab.service.core.method.IMethodTypeService;
import com.google.common.base.Joiner;
import org.springframework.util.CollectionUtils;

/**
 * @author wuzhiyu
 * @Title: MethodTypeServiceImpl
 * @ProjectName brill_lab
 * @Description: TODO
 * @date 2019/2/2214:15
 */
@Service
@Transactional
public class MethodTypeServiceImpl implements IMethodTypeService {
    @Resource
    private MethodTypeMapper methodTypeMapper;
    @Resource
    private IMethodTypeHideService methodTypeHideService;

    @Override
    public MethodType getMethodTypeById(Long typeId) {
        return methodTypeMapper.selectById(typeId);
    }

    @Override
    public MethodTypeDetailVo getMethodFullNameByThirdId(Long thirdTypeId) {
        MethodTypeDetailVo vo = new MethodTypeDetailVo();
        MethodType third = methodTypeMapper.selectById(thirdTypeId);
        MethodType second = methodTypeMapper.selectById(third.getSecondId());
        MethodType first = methodTypeMapper.selectById(third.getFirstId());
        String fullName = Joiner.on("-").join(first.getName(), second.getName(), third.getName());
        vo.setFirstTypeId(third.getFirstId());
        vo.setFirstTypeName(first.getName());
        vo.setSecondTypeId(third.getSecondId());
        vo.setSecondTypeName(second.getName());
        vo.setMethodTypeId(thirdTypeId);
        vo.setMethodTypeName(third.getName());
        vo.setFullName(fullName);
        return vo;
    }

    @Override
    public boolean add(MethodType methodType) {
        return methodTypeMapper.insert(methodType) > 0;
    }

    @Override
    public boolean updateById(MethodType method) {
        return methodTypeMapper.updateById(method) > 0;
    }

    @Override
    public List<MethodType> listRecommendMethodType(Long labId, MethodTypeLevelEnum typeLevel) {
        return methodTypeMapper.listRecommendMethodThirdType(labId, typeLevel.getLevel());
    }

    /*********************************
     * 吴梦昊
     *******************************************/
    @Override
    public MethodType selectOneById(Long typeId) {
        Assert.notNull(typeId, "参数缺失！");
        return methodTypeMapper.selectOne(
                new LambdaQueryWrapper<MethodType>()
                        .eq(MethodType::getId, typeId)
                        .eq(MethodType::getIsDelete, IsDeleteEnum.NO.getValue()));
    }

    @Override
    public boolean delete(MethodType methodType) {
        Assert.notNull(methodType, "参数缺失！");
        methodType.setIsDelete(IsDeleteEnum.YES.getValue());
        return methodTypeMapper.updateById(methodType) > 0;
    }

    @Override
    public List<MethodType> selectThirdListBySecondId(Long secondId, Long userId) {
        Assert.notNull(secondId, "参数缺失！");

        LambdaQueryWrapper<MethodType> wrapper = new LambdaQueryWrapper<>();
        if (userId != null) {
            wrapper.and(wp -> wp.eq(MethodType::getUserId, userId).or().isNull(MethodType::getUserId));
        } else {
            wrapper.isNull(MethodType::getUserId);
        }
        wrapper.eq(MethodType::getSecondId, secondId);
        wrapper.eq(MethodType::getIsDelete, IsDeleteEnum.NO.getValue());

        return methodTypeMapper.selectList(wrapper);
    }

    @Override
    public List<MethodType> selectListByLevelAndParentIdAndUserId(Integer level, Long parentId, Long userId) {
        Assert.isTrue(level != null && userId != null, "参数缺失");
        return methodTypeMapper.selectListByLevelAndParentIdAndUserId(level, parentId, userId);
    }

    @Override
    public boolean updateBatch(List<MethodType> thirdTypes) {
        Assert.isTrue(thirdTypes != null, "参数缺失！");
        return methodTypeMapper.updateBatch(thirdTypes) == thirdTypes.size();
    }

    @Override
    public List<MethodType> selectSecondListByFirstId(Long firstId, Long userId) {
        Assert.notNull(firstId, "参数缺失！");
        LambdaQueryWrapper<MethodType> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(MethodType::getFirstId, firstId);
        wrapper.eq(MethodType::getLevel, MethodTypeLevelEnum.LevelSecond.getLevel());
        wrapper.eq(MethodType::getIsDelete, IsDeleteEnum.NO.getValue());
        if (userId != null) {
            wrapper.and(wp -> wp.eq(MethodType::getUserId, userId).or().isNull(MethodType::getUserId));
        } else {
            wrapper.isNull(MethodType::getUserId);
        }
        return methodTypeMapper.selectList(wrapper);
    }

    @Override
    public List<MethodType> selectThirdListBySecondIdList(List<Long> secondIds, Long userId) {
        Assert.notNull(secondIds, "参数缺失！");
        if (secondIds.size() == 0) {
            return new ArrayList<>();
        }
        LambdaQueryWrapper<MethodType> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(MethodType::getSecondId, secondIds);
        wrapper.eq(MethodType::getIsDelete, IsDeleteEnum.NO.getValue());
        if (userId != null) {
            wrapper.and(wp -> wp.eq(MethodType::getUserId, userId).or().isNull(MethodType::getUserId));
        } else {
            wrapper.isNull(MethodType::getUserId);
        }
        return methodTypeMapper.selectList(wrapper);
    }

    @Override
    public List<RecommendMethodTypeVo> selectRecommendThirdMethodVo(Long userId) {
        Assert.notNull(userId, "参数缺失！");
        return methodTypeMapper.selectRecommendThirdMethodVo(userId);
    }

    @Override
    public List<MethodType> selectReferenceMethodType() {
        return methodTypeMapper.selectList(new LambdaQueryWrapper<MethodType>()
                .in(MethodType::getLevel, MethodTypeLevelEnum.LevelFirst.getLevel(),
                        MethodTypeLevelEnum.LevelSecond.getLevel())
                .eq(MethodType::getIsDelete, IsDeleteEnum.NO.getValue()).isNull(MethodType::getUserId));
    }

    @Override
    public MethodType selectSecondType(String name, Long firstMethodTypeId, Long userId) {
        return methodTypeMapper.selectOne(
                new LambdaQueryWrapper<MethodType>()
                        .eq(MethodType::getName, name)
                        .eq(MethodType::getFirstId, firstMethodTypeId)
                        .eq(MethodType::getLevel, MethodTypeLevelEnum.LevelSecond.getLevel())
                        .eq(MethodType::getIsDelete, IsDeleteEnum.NO.getValue())
                        .and(wrapper -> wrapper.eq(MethodType::getUserId, userId).or().isNull(MethodType::getUserId)));
    }

    @Override
    public MethodType selectThirdType(String name, Long secondId, Long userId) {
        return methodTypeMapper.selectOne(
                new LambdaQueryWrapper<MethodType>()
                        .eq(MethodType::getName, name)
                        .eq(MethodType::getSecondId, secondId)
                        .eq(MethodType::getLevel, MethodTypeLevelEnum.LevelThird.getLevel())
                        .eq(MethodType::getIsDelete, IsDeleteEnum.NO.getValue())
                        .and(wrapper -> wrapper.eq(MethodType::getUserId, userId).or().isNull(MethodType::getUserId)));
    }

    /*********************************
     * end
     *******************************************/

    @Override
    public List<MethodType> listPublicMethodType() {
        LambdaQueryWrapper<MethodType> query = new LambdaQueryWrapper<>();
        query.isNull(MethodType::getUserId);
        query.eq(MethodType::getIsDelete, BoolEnum.FALSE.getValue());
        return methodTypeMapper.selectList(query);
    }

    @Override
    public List<MethodType> listByNameAndUserId(String methodTypeName, Long userId) {
        LambdaQueryWrapper<MethodType> query = new LambdaQueryWrapper<>();
        query.eq(MethodType::getName, methodTypeName);
//        query.eq(MethodType::getUserId, userId).or().isNull(MethodType::getUserId);
        query.eq(MethodType::getIsDelete, BoolEnum.FALSE.getValue());
        query.and(wp -> wp.eq(MethodType::getUserId, userId).or().isNull(MethodType::getUserId));
        // query.eq(MethodType::getLevel, MethodTypeLevelEnum.LevelThird.getLevel());
        return methodTypeMapper.selectList(query);
    }

    @Override
    public List<MethodType> listThreeLevelTypeByThirdId(Long thirdTypeId) {
        MethodType t = methodTypeMapper.selectById(thirdTypeId);
        MethodType s = methodTypeMapper.selectById(t.getSecondId());
        MethodType f = methodTypeMapper.selectById(t.getFirstId());
        List<MethodType> all = new ArrayList<>();
        all.add(t);
        all.add(s);
        all.add(f);
        return all;
    }

    @Override
    public List<MethodType> getThirdTypeList(Long labId, Long userId, int isOwn) {
        return methodTypeMapper.getThirdTypeList(labId, userId, isOwn);
    }

    @Override
    public List<MethodType> listUserAllType(Long userId) {
        LambdaQueryWrapper<MethodType> query = new LambdaQueryWrapper<>();
        query.and(wrapper -> wrapper.eq(MethodType::getUserId, userId).or().isNull(MethodType::getUserId));
        query.eq(MethodType::getIsDelete, IsDeleteEnum.NO.getValue());
        return methodTypeMapper.selectList(query);
    }

    @Override
    public List<MethodType> listByIdList(List<Long> typeIdList) {
        if(!CollectionUtils.isEmpty(typeIdList)){
            LambdaQueryWrapper<MethodType> query = new LambdaQueryWrapper<>();
            query.in(MethodType::getId, typeIdList);
            return methodTypeMapper.selectList(query);
        }
        return new ArrayList<>(0);
    }

    @Override
    public List<MethodType> selectAllFirstMethodType() {
        return methodTypeMapper.selectAllFirstMethodType();
    }

    @Override
    public List<MethodType> getPublicThirdTypeList() {
        LambdaQueryWrapper<MethodType> query = new LambdaQueryWrapper<>();
        query.eq(MethodType::getLevel, MethodTypeLevelEnum.LevelThird.getLevel());
        query.isNull(MethodType::getUserId);
        return methodTypeMapper.selectList(query);
    }

    @Override
    public List<MethodType> getUserAllThirdTypeList(Long userId) {
        LambdaQueryWrapper<MethodType> query = new LambdaQueryWrapper<>();
        query.eq(MethodType::getLevel, MethodTypeLevelEnum.LevelThird.getLevel());
        query.isNull(MethodType::getUserId).or().eq(MethodType::getUserId,userId);
        return methodTypeMapper.selectList(query);
    }

    @Override
    public List<MethodType> selectList(Long userId,boolean includeHide) {
        return this.selectList(null,null,null,userId,includeHide);
    }

    @Override
    public List<String> selectAllThirdMethodPrefix(Long secondTypeId,Long userId) {
        return methodTypeMapper.selectAllThirdMethodPrefix(secondTypeId,userId);
    }

    @Override
    public int deleteByMethodTypeIds(List<Long> methodTypeIds,Long userId) {
        if(!CollectionUtils.isEmpty(methodTypeIds)){
            methodTypeHideService.deleteByMethodTypeIds(methodTypeIds,userId);
            return methodTypeMapper.deleteByMethodTypeIds(methodTypeIds,userId);
        }
        return 0;
    }

    @Override
    public int selectCount(Long parentId,Integer level,String name,Long userId) {
        LambdaQueryWrapper<MethodType> wrapper=getMethodTypeQueryWrapper(parentId,level,name,userId);
        return methodTypeMapper.selectCount(wrapper);
    }

    @Override
    public List<MethodType> selectFreqUseThirdMethod(Long userId) {
        return methodTypeMapper.selectFreqUseThirdMethod(userId);
    }

    @Override
    public List<MethodType> selectTopFreqUseThirdMethod(Long userId) {
        return methodTypeMapper.selectTopFreqUseThirdMethod(userId);
    }

    @Override
    public List<MethodType> selectList(Long parentId,Integer level,String name,Long userId,boolean includeHide) {
        LambdaQueryWrapper<MethodType> wrapper=getMethodTypeQueryWrapper(parentId,level,name,userId);
        List<MethodType> methodTypes=methodTypeMapper.selectList(wrapper);
        //隐藏
        if(!includeHide){
            List<MethodTypeHide> methodTypeHides=methodTypeHideService.selectListByUserId(userId);
            List<Long> hideIds=methodTypeHides.stream().map(MethodTypeHide::getMethodTypeId).distinct().collect(Collectors.toList());
            methodTypes =methodTypes.stream().filter(e -> !hideIds.contains(e.getId())).collect(Collectors.toList());
        }
        return methodTypes;
    }

    private LambdaQueryWrapper<MethodType> getMethodTypeQueryWrapper(Long parentId,Integer level,String name,Long userId) {
        LambdaQueryWrapper<MethodType> wrapper=new LambdaQueryWrapper<MethodType>()
                .and(e -> e.eq(MethodType::getUserId,userId).or().isNull(MethodType::getUserId))
                .eq(MethodType::getIsDelete,BoolEnum.FALSE.getValue());

        if(level!=null){
            wrapper.eq(MethodType::getLevel,level);
        }

        if(StringUtils.isNotBlank(name)){
            wrapper.like(MethodType::getName,name.trim());
        }

        if(parentId!=null && level!=null){
            if(level.equals(MethodTypeLevelEnum.LevelThird.getLevel())){
                //三级
                wrapper.eq(MethodType::getSecondId,parentId);
            }else if(level.equals(MethodTypeLevelEnum.LevelSecond.getLevel())){
                //二级
                wrapper.eq(MethodType::getFirstId,parentId);
            }
        }
        return wrapper;
    }
}
